#ifndef LVGAME_ASTAR_H
#define LVGAME_ASTAR_H

#include <vector>

namespace LVGame {

struct Point {
    Point():
        x(0), y(0) {}
    Point(int _x, int _y):
        x(_x), y(_y) {}

    int x;
    int y;
};

class AStar {
public:
    void operator()(const int *search_map, int x_max, int y_max,
                    const Point &start_pos, const Point &end_pos,
                    std::vector<Point> *result_path);
private:
    struct Node {
        Point pos;
        bool is_walkable;
        int f;
        int g;
        int open_list_pos;
        int close_list_pos;
        Node* parent;
    };

    struct NodeFScoreLower {
        bool operator()(const Node *lhs, const Node *rhs);
    };

    struct NodeNeighborGCost {
        int operator()(const Node *lhs, const Node *rhs);
    };

    struct HeursiticCostEstimate {
        int operator()(const Node *lhs, const Node *rhs);
    };

private:
    std::vector<Node> m_grid;
    int m_x_max;
    int m_y_max;
    Node *m_start_node;
    Node *m_end_node;
    std::vector<Node *> m_open_list;

private:
    void init(const int *search_map, int x_max, int y_max,
              const Point &start_pos, const Point &end_pos);
    void constructResultPath(std::vector<Point> *result_path);

    Node *getNode(const Point &pos);
    void getNeighborNodes(const Node *node,
                          std::vector<Node *> *neighbor_nodes);

    void initOpenList();
    bool isInOpenList(const Node *node) const;
    bool isOpenListEmpty() const;
    void insertOpenList(Node* node);
    Node *getMinFScoreNodeInOpenList();
    void deleteMinFScoreNodeInOpenList();
    void resortOpenList(Node* node);

    bool isInCloseList(const Node *node) const;
    void insertCloseList(Node *node);
};

}; // end of namespace

#endif

